#lang scheme

;; if you are still familiar with the ebnf we mentioned
;; in the first class, it may not be very hard for you 
;; to recall the rule syntax:
;; <sentence> ::= <noun-phrase> <verb-phrase>
;; <noun-phrase> ::= <article> <noun>
;; <verb-phrase> ::= <verb> <noun-phrase>
;; <article> :: "the" | "a"
;; <noun> ::= "man" | "ball" | "woman" | "table"
;; <verb> ::= "hit" | "took" | "saw" | "liked"
(define rules
  '((sentence ::= noun-phrase verb-phrase)
    (noun-phrase ::= Article Noun)
    (verb-phrase ::= Verb noun-phrase)
    (Article ::= (the a))
    (Noun ::= (man ball woman table))
    (Verb ::= (hit took saw liked))))

(define (generate-by rules)
  (define (one-of list)
    (if (or (empty? (cdr list))
          (= (random 2) 0))
      (car list)
      (one-of (cdr list))))
  
  ;; find the tag
  ;; the tag is the first item of the list:
  ;; ((tag ::= ...) ...)
  (define (get-tag rule tag)
    (let ((the-tag (caar rule)))
      (if (eq? the-tag tag)
          (car rule)
          (get-tag (cdr rule) tag))))

  ;; evaluation by the tag
  ;; ... ::= tag (list)
  ;; eval the tag and choose one of the list
  ;; the rule could be more complex,
  ;; say that the one choose could also be
  ;; a tag of the syntax... 
  (define (eval-tag tag)
    (let ((exp (cddr (get-tag rules tag))))
      (map
       (lambda (item)
         (if (list? item)
             (one-of item)
             (eval-tag item)))
       exp)))

  (flatten (eval-tag (car (car rules)))))

;; generate-code-process-the-rules.rkt> (generate-by rules)
;; (the man took the ball)
